package com.survivingwithandroid.charts;
import android.app.Fragment;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.survivingwithandroid.weather.lib.WeatherClient;
import com.survivingwithandroid.weather.lib.WeatherConfig;
import com.survivingwithandroid.weather.lib.client.volley.WeatherClientDefault;
import com.survivingwithandroid.weather.lib.exception.WeatherLibException;
import com.survivingwithandroid.weather.lib.model.DayForecast;
import com.survivingwithandroid.weather.lib.model.HourForecast;
import com.survivingwithandroid.weather.lib.model.WeatherForecast;
import com.survivingwithandroid.weather.lib.model.WeatherHourForecast;
import com.survivingwithandroid.weather.lib.provider.IWeatherProvider;
import com.survivingwithandroid.weather.lib.provider.WeatherProviderFactory;
import com.survivingwithandroid.weather.lib.provider.openweathermap.OpenweathermapProviderType;
import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.BarChart;
import org.achartengine.chart.PointStyle;
import org.achartengine.model.RangeCategorySeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.List;
/**
* ${copyright}.
*/
public class ChartFragment extends Fragment {
private LinearLayout chartLyt;
private Animation fadeAnim;
// London, UK
private static final String CITY_ID = "2643743";
private List<DayForecast> dayForecast;
private List<HourForecast> nextHourForecast;
/**
* Called when the fragment's activity has been created and this
* fragment's view hierarchy instantiated. It can be used to do final
* initialization once these pieces are in place, such as retrieving
* views or restoring state. It is also useful for fragments that use
* {@link #setRetainInstance(boolean)} to retain their instance,
* as this callback tells the fragment when it is fully associated with
* the new activity instance. This is called after {@link #onCreateView}
* and before {@link #onViewStateRestored(android.os.Bundle)}.
*
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
fadeAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_anim);
getData();
}
/**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
* {@link #onCreate(android.os.Bundle)} and {@link #onActivityCreated(android.os.Bundle)}.
* <p/>
* <p>If you return a View from here, you will later be called in
* {@link #onDestroyView} when the view is being released.
*
* @param inflater The LayoutInflater object that can be used to inflate
* any views in the fragment,
* @param container If non-null, this is the parent view that the fragment's
* UI should be attached to. The fragment should not add the view itself,
* but this can be used to generate the LayoutParams of the view.
* @param savedInstanceState If non-null, this fragment is being re-constructed
* from a previous saved state as given here.
* @return Return the View for the fragment's UI, or null.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
chartLyt = (LinearLayout) v.findViewById(R.id.chart);
return v;
}
private void getData() {
WeatherClient client = setupClient(getActivity());
client.getHourForecastWeather(CITY_ID, new WeatherClient.HourForecastWeatherEventListener() {
@Override
public void onWeatherRetrieved(WeatherHourForecast weatherHourForecast) {
nextHourForecast = weatherHourForecast.getHourForecast();
Toast.makeText(getActivity(), "Data retrieved", Toast.LENGTH_LONG).show();
chartLyt.addView(createTempGraph(), 0);
}
@Override
public void onWeatherError(WeatherLibException e) {
Toast.makeText(getActivity(), "Error parsing the data", Toast.LENGTH_LONG).show();
}
@Override
public void onConnectionError(Throwable throwable) {
Toast.makeText(getActivity(), "Error connecting to the remove weather server!", Toast.LENGTH_LONG).show();
}
});
client.getForecastWeather(CITY_ID, new WeatherClient.ForecastWeatherEventListener() {
@Override
public void onWeatherRetrieved(WeatherForecast weatherForecast) {
dayForecast = weatherForecast.getForecast();
Toast.makeText(getActivity(), "Forecast retrieved!", Toast.LENGTH_LONG).show();
}
@Override
public void onWeatherError(WeatherLibException e) {
Log.e("SwA", "#####à ERROR #####", e);
Toast.makeText(getActivity(), "Forecast: Error parsing the data", Toast.LENGTH_LONG).show();
}
@Override
public void onConnectionError(Throwable throwable) {
Toast.makeText(getActivity(), "Forecast: Error connecting to the remove weather server!", Toast.LENGTH_LONG).show();
}
});
}
private WeatherClient setupClient(Context ctx) {
WeatherClient client = WeatherClientDefault.getInstance();
client.init(ctx);
WeatherConfig config = new WeatherConfig();
config.unitSystem = WeatherConfig.UNIT_SYSTEM.M;
config.numDays = 6;
try {
IWeatherProvider provider = WeatherProviderFactory.createProvider(new OpenweathermapProviderType(), config);
client.setProvider(provider);
}
catch (Throwable t) {
t.printStackTrace();
// There's a problem
}
return client;
}
private View createTempGraph() {
// We start creating the XYSeries to plot the temperature
XYSeries series = new XYSeries("London Temperature hourly");
// We start filling the series
int hour = 0;
for (HourForecast hf : nextHourForecast) {
series.add(hour++, hf.weather.temperature.getTemp());
}
// Now we create the renderer
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setLineWidth(2);
renderer.setColor(Color.RED);
// Include low and max value
renderer.setDisplayBoundingPoints(true);
// we add point markers
renderer.setPointStyle(PointStyle.CIRCLE);
renderer.setPointStrokeWidth(3);
// Now we add our series
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series);
// Finaly we create the multiple series renderer to control the graph
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
mRenderer.addSeriesRenderer(renderer);
// We want to avoid black border
mRenderer.setMarginsColor(Color.argb(0x00, 0xff, 0x00, 0x00)); // transparent margins
// Disable Pan on two axis
mRenderer.setPanEnabled(false, false);
mRenderer.setYAxisMax(35);
mRenderer.setYAxisMin(0);
mRenderer.setShowGrid(true); // we show the grid
GraphicalView chartView = ChartFactory.getLineChartView(getActivity(), dataset, mRenderer);
// Enable chart click
mRenderer.setClickEnabled(true);
chartView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
applyAnim(v, createPressGraph());
}
});
return chartView;
}
private View createPressGraph() {
XYSeries series = new XYSeries("London Pressure hourly");
// We start filling the series
int hour = 0;
for (HourForecast hf : nextHourForecast) {
series.add(hour++, hf.weather.currentCondition.getPressure());
if (hour > 24)
break;
}
// Now we create the renderer
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setColor(Color.BLUE);
// Include low and max value
renderer.setDisplayBoundingPoints(true);
// Now we add our series
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series);
// Finaly we create the multiple series renderer to control the graph
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
mRenderer.addSeriesRenderer(renderer);
// We want to avoid black border
mRenderer.setMarginsColor(Color.argb(0x00, 0xff, 0x00, 0x00)); // transparent margins
// Disable Pan on two axis
mRenderer.setPanEnabled(false, false);
mRenderer.setShowGrid(true); // we show the grid
mRenderer.setBarSpacing(1);
GraphicalView chartView = ChartFactory.getBarChartView(getActivity(), dataset, mRenderer, BarChart.Type.DEFAULT);
// Enable chart click
mRenderer.setClickEnabled(true);
chartView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
applyAnim(v, createForecastTemp());
}
});
return chartView;
}
private View createForecastTemp() {
RangeCategorySeries series = new RangeCategorySeries("London next days temperature");
// We start filling the series
int hour = 0;
SimpleDateFormat sdf = new SimpleDateFormat("dd,MMM");
// We create the multiple series renderer to control the graph
XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
for (DayForecast df : dayForecast) {
series.add(df.forecastTemp.min, df.forecastTemp.max);
mRenderer.addXTextLabel(hour++, sdf.format(df.timestamp));
}
//renderer.setGradientStop(20, Color.RED);
// Now we add our series
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series.toXYSeries());
// We want to avoid black border
mRenderer.setMarginsColor(Color.argb(0x00, 0xff, 0x00, 0x00)); // transparent margins
// Disable Pan on two axis
mRenderer.setPanEnabled(false, false);
mRenderer.setShowGrid(true); // we show the grid
mRenderer.setBarSpacing(0.5);
mRenderer.setMargins(new int[] {30, 70, 10, 0});
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setDisplayChartValues(true);
mRenderer.addSeriesRenderer(renderer);
mRenderer.setYAxisMax(30.0);
mRenderer.setYAxisMin(0.0);
renderer.setChartValuesTextSize(12);
renderer.setChartValuesFormat(new DecimalFormat("#.##"));
renderer.setColor(Color.GREEN);
GraphicalView chartView = ChartFactory.getRangeBarChartView(getActivity(), dataset, mRenderer, BarChart.Type.DEFAULT);
// Enable chart click
mRenderer.setClickEnabled(true);
chartView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
applyAnim(v, createTempGraph());
}
});
return chartView;
}
private void applyAnim(final View v, final View nextView) {
Animation.AnimationListener list = new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
chartLyt.removeViewAt(0);
chartLyt.addView(nextView,0);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
};
fadeAnim.setAnimationListener(list);
v.startAnimation(fadeAnim);
}
}